﻿using System.Reflection;
using System.Text;
using SqlSugar;
using Zero.WebAPI.Framework.Helper;

namespace Zero.WebAPI.Framework.DAL
{
    public class SugarDbContext : IDisposable
    {
        public static List<ConnectionConfig> ConnectionConfigs { get; private set; }

        public SqlSugarClient DB { get; }
        public string ConfigId
        {
            get
            {
                return DB.CurrentConnectionConfig.ConfigId.ToString();
            }
        }

        public SugarDbContext(ConnectionConfig config, Action<SqlSugarClient> configAction = null)
        {
            DB = new SqlSugarClient(config, configAction);
        }

        public SugarDbContext(List<ConnectionConfig> _connectionConfigs,Action<SqlSugarClient> configAction = null)
        {
            ConnectionConfigs = _connectionConfigs;
            DB = new SqlSugarClient(_connectionConfigs,configAction);
        }

        /// <summary>
        /// 根据表结构生成实体类
        /// </summary>
        /// <param name="configId"></param>
        /// <param name="namesp"></param>
        public void GenerateModels(string configId, string modelPath, string ignorePrefix = "", 
            string namesp = "Default.Models", Action<string> processLog = null)
        {
            if (!Directory.Exists(modelPath))
                Directory.CreateDirectory(modelPath);
            DB.GetConnection(configId)
                .DbFirst
                .IsCreateAttribute()
                .FormatFileName(arg1 =>
                {
                    if (!string.IsNullOrEmpty(ignorePrefix))
                    {
                        arg1 = arg1.Replace(ignorePrefix, "");
                    }
                    arg1 = arg1.Replace("_", "");
                    return char.ToUpper(arg1[0]) + arg1.Substring(1);
                })
                .FormatClassName(arg1 =>
                {
                    if (!string.IsNullOrEmpty(ignorePrefix))
                    {
                        arg1 = arg1.Replace(ignorePrefix, "");
                    }
                    arg1 = arg1.Replace("_", "");
                    return char.ToUpper(arg1[0]) + arg1.Substring(1);
                })
                .SettingNamespaceTemplate(arg1 =>
                {
                    return arg1 += "using System.ComponentModel.DataAnnotations;\n";
                })
                .SettingPropertyTemplate((column, arg1, arg2) =>
                {
                    // 初始化用于拼接的字符串
                    StringBuilder builder = new StringBuilder("\n");
                    string propertyStr = $"\t\t   public {arg2} {ConvertToPascalCase(column.DbColumnName)} {{get; set;}}";

                    int len = column.Length;
                    if (arg2.Contains("DateTime", StringComparison.OrdinalIgnoreCase))
                        len = 0;
                    // 如果字段是主键，则添加 [SugarColumn(IsPrimaryKey=true)] 特性
                    if (column.IsPrimarykey)
                    {
                        builder.AppendLine($"\t\t   [SugarColumn(IsPrimaryKey=true,ColumnName =\"{column.DbColumnName}\",ColumnDescription = \"{column.ColumnDescription}\",Length = {len})]");
                    }
                    else
                    {
                        builder.AppendLine($"\t\t   [SugarColumn(ColumnName =\"{column.DbColumnName}\",ColumnDescription = \"{column.ColumnDescription}\",Length = {len})]");
                    }

                    // 如果字段可以为空，字段类型后面加？否则则添加 [Required] 特性
                    if (!column.IsNullable)
                    {
                        builder.AppendLine("\t\t   [Required]");
                    }

                    // 拼接属性
                    builder.AppendLine(propertyStr);
                    string logInfo = $"正在生成表： {column.TableName} 对应的实体类属性：{arg2} {column.DbColumnName} ...";

                    processLog?.Invoke(logInfo);

                    // 返回处理后的字段属性字符串
                    return builder.ToString();
                })
                .CreateClassFile(modelPath, namesp);
        }

        /// <summary>
        /// 将字符串转换为帕斯卡命名法
        /// </summary>
        /// <param name="name">需要变动的名称：user_id => UserId</param>
        /// <returns></returns>
        private string ConvertToPascalCase(string name)
        {
            if (name.Contains("_"))
                name = string.Concat(name.Split('_').Select(word => char.ToUpper(word[0]) + word.Substring(1).ToLower()));
            else
                name = char.ToUpper(name[0]) + name.Substring(1);
            return name;
        }

        /// <summary>
        /// 根据实体类生成数据表
        /// </summary>
        /// <param name="configId"></param>
        public void GenerateTables(string configId,string assemblyName)
        {
            Assembly assembly = Assembly.Load(assemblyName);
            List<Type> types = assembly.GetTypes().Where(s => s.GetCustomAttribute<SugarTable>() != null).ToList();
            ConnectionConfig? connConfig = ConnectionConfigs.FirstOrDefault(c => c.ConfigId == configId);
            if (connConfig == null)
                throw new Exception("指定的数据源Id未找到");
            SqlSugarClient sourceContext = new SqlSugarClient(connConfig, db =>
            {
                //db.Aop.OnLogExecuting = (sql, parameters) =>
                //{
                //    ConsoleLog.Info($"SQL 执行完成：{sql}");
                //};

                db.Aop.OnError = (exp) =>
                {
                    LogHelper.Error($"SQL 执行出错：{exp.Message}");
                };
            });

            sourceContext
                .CodeFirst
                .InitTablesWithAttr(types.ToArray());
        }


        public void Dispose()
        {
            DB?.Close();
            DB?.Dispose();
        }
    }
}
